<?php
/**
 * 小蜗牛留言本
 * 本文件内代码属于“小蜗牛留言本”项目，禁止修改再发布本程序源码，禁止去除页面底部的版权申明。所有版权保留
 * User: upliu
 * Email: 753073861@qq.com
 * QQ: 753073861
 * 程序主页：http://demo.upliu.net/snail-guestbook/
 */


function echo_json_success($message = '', $data = array())
{
    echo json_encode(array(
        'message' => $message,
        'status' => 0,
        'data' => $data
    ));
}

function echo_json_error($message = '', $status = 1, $data = array())
{
    echo json_encode(array(
        'message' => $message,
        'status' => $status,
        'data' => $data
    ));
}

function is_has_success_message()
{
    return !empty($_SESSION['success_message']);
}

function is_has_error_message()
{
    return !empty($_SESSION['error_message']);
}

function set_success_message($msg)
{
    $_SESSION['success_message'] = $msg;
}

function set_error_message($msg)
{
    $_SESSION['error_message'] = $msg;
}

function get_success_message($keep = false)
{
    if (empty($_SESSION['success_message'])) {
        return '';
    }

    $msg = $_SESSION['success_message'];
    if (!$keep) {
        unset($_SESSION['success_message']);
    }
    return $msg;
}

function get_error_message($keep = false)
{
    if (empty($_SESSION['error_message'])) {
        return '';
    }

    $msg = $_SESSION['error_message'];
    if (!$keep) {
        unset($_SESSION['error_message']);
    }
    return $msg;
}

function html_select_render($options, $prompt = '', $config)
{
    $config += array(
        'name' => '',
        'class' => '',
        'selected' => '',
    );
    $os = array();
    if ($prompt) {
        $os[] = "<option>$prompt</option>";
    }
    foreach ($options as $k => $v) {
        $os[] = "<option" . ($k == $config['selected'] ? ' selected' : '') . " value='".htmlentities($k)."'>".htmlentities($v)."</option>";
    }

    return "<select name='{$config['name']}' class='{$config['class']}'>" . implode("\n", $os) . "</select>";
}

function e_if_true($var, $format)
{
    if ($var) {
        e(sprintf($format, $var));
    }
}

function e($str)
{
    echo htmlspecialchars($str, ENT_COMPAT | ENT_HTML401, 'UTF-8');
}

function echo_active_if_true($link)
{
    if (is_active_menu($link)) {
        echo 'active';
    }
}

function is_active_menu($link)
{
    if (stripos(get_script_url(), $link) !== false) {
        return true;
    }

    return false;
}

/**
 * 跳转到后台首页
 */
function redirect_admin_home()
{
    redirect_path('admin');
}

/**
 * 跳转到前台首页
 */
function redirect_home()
{
    redirect_path('');
}

function redirect_path($path)
{
    $project_url = get_project_url();
    $url = $project_url . '/' . ltrim($path, '/');
    header('Location: ' . $url);
    exit();
}

function static_url($path)
{
    $path = '/views/' . ltrim($path, '/');
    echo get_project_url() . $path;
}

function get_project_url()
{
    static $project_url;
    if ($project_url === null) {
        $project_url = preg_replace('#admin$#', '', get_base_url());
        $project_url = rtrim($project_url, '/');
    }

    return $project_url;
}

function renderWithLayout($__view_name, $__data = array())
{
    $conent = render($__view_name, $__data);
    return render('layout', $__data + array(
        '__content' => $conent,
    ));
}

function renderWithAdminLayout($__view_name, $__data = array())
{
    $conent = render($__view_name, $__data);
    $conent_with_admin_layout = render('admin/layout', $__data + array(
            '__content' => $conent,
        ));
    return render('layout', $__data = array(
        '__content' => $conent_with_admin_layout,
    ));
}

/**
 * 渲染视图
 * @param $__view_name
 * @param array $__data
 * @param bool|true $echo
 * @return bool
 */
function render($__view_name, $__data = array())
{
    extract($__data, EXTR_SKIP);
    $__dir = getcwd();
    chdir(DIR_VIEWS);
    ob_start();
    $old_levle = error_reporting();
    // 禁掉 E_NOTICE 级别错误，减少视图里面的一些判断
    error_reporting($old_levle & ~E_NOTICE);
    include DIR_VIEWS . '/' . $__view_name . '.php';
    error_reporting($old_levle);
    $buff = ob_get_clean();
    chdir($__dir);

    return $buff;
}

function pagination($url, $total_count, $page_size, $current_page = 1, $page_param = 'page', $link_num = 10)
{
    $url = rtrim($url, '?');
    $last_page = ceil($total_count / $page_size);
    $first_page = 1;
    // 一共只有 1 页情况，我们不显示分页按钮
    if ($last_page < 2) {
        return '';
    }

    $href_elements = array();
    if ($current_page == $first_page) {
        $href_elements[] = "<li class='disabled first'><span>首页</span></li>";
        $href_elements[] = "<li class='disabled prev'><span>上一页</span></li>";
    } else {
        $first_href = add_query_to_url($url, $page_param);
        $prev_href = add_query_to_url($url, $page_param, $current_page - 1);
        $href_elements[] = "<li class='first'><a href='$first_href'>首页</a></li>";
        $href_elements[] = "<li class='prev'><a href='$prev_href'>上一页</a></li>";
    }

    $begin_page = max(1, $current_page - ceil($link_num / 2));
    if (($end_page = $begin_page + $link_num - 1) > $last_page) {
        $end_page = $last_page;
        $begin_page = max(1, $end_page - $link_num + 1);
    }
    for ($i = $begin_page; $i <= $end_page; $i++) {
        if ($i == $current_page) {
            $href_elements[] = "<li class='active'><span>$i</span></li>";
        } else {
            $href_elements[] = "<li><a href='" . add_query_to_url($url, $page_param, $i) . "'>$i</a></li>";
        }
    }

    if ($current_page == $last_page) {
        $href_elements[] = "<li class='disabled next'><span>下一页</span></li>";
        $href_elements[] = "<li class='disabled last'><span>末页</span></li>";
    } else {
        $last_href = add_query_to_url($url, $page_param, $last_page);
        $next_href = add_query_to_url($url, $page_param, $current_page + 1);
        $href_elements[] = "<li class='next'><a href='$next_href'>下一页</a></li>";
        $href_elements[] = "<li class='last'><a href='$last_href'>末页</a></li>";
    }

    return "<div class='pagination-wrap'><ul class='pagination'>\n" . implode("\n", $href_elements) . "\n</ul></div>";
}

/**
 * 检查访问的页码是否超出总数
 * @param $page
 * @param $total_count
 * @param $page_size
 * @param bool|true $throw_exception
 * @return bool
 * @throws Exception
 */
function check_is_correct_page($page, $total_count, $page_size, $throw_exception = true)
{
    $last_page = ceil($total_count / $page_size);
    if ($page < 1 || ($last_page > 0 && $page > $last_page)) {
        if ($throw_exception) {
            throw new Exception('The page you are looking for is not found.', 404);
        }

        return false;
    }

    return true;
}

function add_query_to_url($url, $param, $value = null)
{
    $parsed = parse_url($url);
    if (empty($parsed['query'])) {
        if ($value !== null) {
            return $url . '?' . http_build_query(array($param => $value));
        } else {
            return rtrim($url, '?');
        }
    }

    $params = array();
    parse_str($parsed['query'], $params);
    if ($value !== null) {
        $params[$param] = $value;
    } else {
        unset($params[$param]);
    }

    $scheme = isset($parsed['scheme']) ? $parsed['scheme'] . '://' : '';
    $host = isset($parsed['host']) ? $parsed['host'] : '';
    $port = isset($parsed['port']) ? ':' . $parsed['port'] : '';
    $user = isset($parsed['user']) ? $parsed['user'] : '';
    $pass = isset($parsed['pass']) ? ':' . $parsed['pass'] : '';
    $pass = ($user || $pass) ? "$pass@" : '';
    $path = isset($parsed['path']) ? $parsed['path'] : '';
    $query = !empty($params) ? ('?'.http_build_query($params)) : '';
    $fragment = isset($parsed['fragment']) ? '#' . $parsed['fragment'] : '';
    return "$scheme$user$pass$host$port$path$query$fragment";
}

/**
 * 该函数参考了 yii2 框架的相关代码
 * @return mixed|string
 * @throws Exception
 * @see \yii\web\Request::getBaseUrl()
 */
function get_base_url()
{
    static $baseUrl;
    if ($baseUrl === null) {
        $baseUrl = rtrim(dirname(get_script_url()), '\\/');
    }

    return $baseUrl;
}

/**
 * 该函数参考了 yii2 框架的相关代码
 * @return mixed|string
 * @throws Exception
 * @see \yii\web\Request::getHostInfo()
 */
function get_host_info()
{
    static $host_info;
    if (!$host_info) {
        $secure = isset($_SERVER['HTTPS']) && (strcasecmp($_SERVER['HTTPS'], 'on') === 0 || $_SERVER['HTTPS'] == 1)
            || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0;

        $port = isset($_SERVER['SERVER_PORT'])
            ? (int)$_SERVER['SERVER_PORT']
            : ($secure ? 443 : 80);

        $http = $secure ? 'https' : 'http';
        if (isset($_SERVER['HTTP_HOST'])) {
            $host_info = $http . '://' . $_SERVER['HTTP_HOST'];
        } else {
            $host_info = $http . '://' . $_SERVER['SERVER_NAME'];
            if (($port !== 80 && !$secure) || ($port !== 443 && $secure)) {
                $host_info .= ':' . $port;
            }
        }
    }

    return $host_info;
}

/**
 * 该函数参考了 yii2 框架的相关代码
 * @return mixed|string
 * @throws Exception
 * @see \yii\web\Request::getScriptUrl()
 */
function get_script_url()
{
    static $scriptUrl;
    if ($scriptUrl === null) {
        $scriptFile = $_SERVER['SCRIPT_FILENAME'];
        $scriptName = basename($scriptFile);
        if (basename($_SERVER['SCRIPT_NAME']) === $scriptName) {
            $scriptUrl = $_SERVER['SCRIPT_NAME'];
        } elseif (basename($_SERVER['PHP_SELF']) === $scriptName) {
            $scriptUrl = $_SERVER['PHP_SELF'];
        } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $scriptName) {
            $scriptUrl = $_SERVER['ORIG_SCRIPT_NAME'];
        } elseif (($pos = strpos($_SERVER['PHP_SELF'], '/' . $scriptName)) !== false) {
            $scriptUrl = substr($_SERVER['SCRIPT_NAME'], 0, $pos) . '/' . $scriptName;
        } elseif (!empty($_SERVER['DOCUMENT_ROOT']) && strpos($scriptFile, $_SERVER['DOCUMENT_ROOT']) === 0) {
            $scriptUrl = str_replace('\\', '/', str_replace($_SERVER['DOCUMENT_ROOT'], '', $scriptFile));
        } else {
            throw new Exception('Unable to determine the entry script URL.', 500);
        }
    }

    return $scriptUrl;
}

function get_client_ip()
{
    return $_SERVER['REMOTE_ADDR'];
}

/**
 * array_column 这个函数从 PHP5.5.0 开始自带
 * 模仿该函数功能使得低版本 PHP 也可以使用该函数
 */
if (!function_exists('array_column')) {
    function array_column(array $array, $column, $index_key = null)
    {
        $result = array();
        foreach ($array as $item) {
            if ($index_key !== null) {
                $result[$item[$index_key]] = $item[$column];
            } else {
                $result[] = $item[$column];
            }
        }

        return $result;
    }
}

function array_index($input, $key, $limit = false)
{
    $input = (array)$input;
    $result = array();
    foreach ($input as $item) {
        if ($limit) {
            $result[$item[$key]] = $item;
        } else {
            $result[$item[$key]][] = $item;
        }
    }

    return $result;
}

class Db
{

    public $dsn;
    public $username;
    public $password;

    public $lastRunStatement;

    /**
     * @param array $config
     * @return static
     */
    public static function getInstance($config = array())
    {
        if (static::$_instance === null) {
            if (empty($config)) {
                $config = include __DIR__ . '/../config.php';
                $config = array_merge(array(
                    'host' => 'localhost',
                    'port' => 3306,
                    'password' => '',
                ), $config);
            }
            
            static::$_instance = new static($config['host'], $config['dbname'], $config['username'], $config['password'], $config['port']);
        }
        
        return static::$_instance;
    }

    protected static $_instance;
    protected function __construct($host, $dbname, $username, $password = '', $port = 3306)
    {
        $this->dsn = "mysql:host=$host;port=$port;dbname=$dbname;charset=utf8";
        $this->username = $username;
        $this->password = $password;
    }

    protected $_pdo;
    public function getConnection()
    {
        if ($this->_pdo === null) {
            $options = array(
                PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
            );
            $this->_pdo = new PDO($this->dsn, $this->username, $this->password, $options);
            $this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }

        return $this->_pdo;
    }

    protected function doExecute($statement, $params = array())
    {
        $this->lastRunStatement = $statement;
        $stmt = $this->getConnection()->prepare($statement);
        $stmt->execute($params);
        return $stmt;
    }

    public function lastInsertId()
    {
        return $this->getConnection()->lastInsertId();
    }

    public function update($table, array $data, $where = '')
    {
        $statement = "update `$table` set ";
        $columns = array();
        $values = array();
        foreach ($data as $column => $value) {
            $columns[] = "`$column`=?";
            $values[] = $value;
        }
        $statement .= implode(',', $columns);
        if (!empty($where)) {
            $statement .= " where $where";
        }
        return $this->execute($statement, $values);
    }

    public function insert($table, array $data)
    {
        $statement = "insert `$table` set ";
        $columns = array();
        $values = array();
        foreach ($data as $column => $value) {
            $columns[] = "`$column`=?";
            $values[] = $value;
        }
        $statement .= implode(',', $columns);
        $this->execute($statement, $values);

        return $this->lastInsertId();
    }

    public function execute($statement, $params = array())
    {
        return $this->doExecute($statement, $params)->rowCount();
    }

    public function query($statement, $params = array())
    {
        return $this->doExecute($statement, $params)->fetch();
    }

    public function queryColumn($statement, $params = array())
    {
        return $this->doExecute($statement, $params)->fetchColumn(0);
    }

    public function queryAll($statement, $params = array())
    {
        return $this->doExecute($statement, $params)->fetchAll();
    }

    /**
     * $values 里面传过来的值并没有进行转义，因此调用这个方法时请注意 SQL 注入的风险
     * @param $statement
     * @param $column
     * @param $values
     * @param array $params
     * @return array
     */
    public function queryAllWhereIn($statement, $column, $values, $params = array())
    {
        if (stripos($statement, 'where') === false) {
            $statement .= ' where 1=1 ';
        }
        $statement .= " and `$column` in ('" . implode("','", $values) . "')";
        return $this->doExecute($statement, $params)->fetchAll();
    }
}